using System;
using System.IO;
using System.Windows.Forms;
using System.Threading.Tasks;
using System.Linq;
using System.Collections.Concurrent;
using System.Diagnostics;

namespace SafeShrink
{
    /// <summary>
    /// 主窗体类，负责磁盘清理功能的主要逻辑
    /// </summary>
    public partial class MainForm : Form
    {
        private Logger logger;  // 日志记录器实例
        private long totalBytesToFree;  // 可释放的总字节数
        private long bytesFreed;  // 已释放的字节数

        /// <summary>
        /// 主窗体构造函数
        /// </summary>
        public MainForm()
        {
            InitializeComponent();
            try
            {
                logger = new Logger();  // 初始化日志记录器
                try 
                {
                    LoadDrives();  // 加载可用驱动器列表
                }
                catch (UnauthorizedAccessException ex)
                {
                    logger.LogWarning($"加载驱动器列表时遇到权限问题: {ex.Message}");
                    // 继续运行，但驱动器列表可能不完整
                }
                catch (Exception ex)
                {
                    logger.LogError($"加载驱动器列表错误: {ex.Message}");
                    // 继续运行，但驱动器列表可能为空
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"应用程序初始化失败: {ex.Message}\n\n程序将退出", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                Environment.Exit(1);
            }
        }

        /// <summary>
        /// 处理启动参数
        /// </summary>
        /// <param name="args">命令行参数</param>
        public void HandleStartupArgs(string[] args)
        {
            try
            {
                logger.LogInfo($"处理启动参数: {string.Join(" ", args)}");

                // 示例: 处理驱动器参数
                if (args.Length > 0 && args[0].Length == 1 && char.IsLetter(args[0][0]))
                {
                    char driveLetter = char.ToUpper(args[0][0]);
                    if (cmbDrives.Items.Contains(driveLetter.ToString()))
                    {
                        cmbDrives.SelectedItem = driveLetter.ToString();
                        logger.LogInfo($"已设置默认驱动器: {driveLetter}:");
                    }
                }
            }
            catch (Exception ex)
            {
                logger.LogError($"处理启动参数错误: {ex.Message}");
            }
        }

        /// <summary>
        /// 加载系统中所有可用的驱动器
        /// </summary>
        private void LoadDrives()
        {
            cmbDrives.Items.Clear();  // 清空现有驱动器列表
            // 获取所有已就绪的驱动器并提取驱动器字母
            var drives = DriveInfo.GetDrives()
                .Where(d => d.IsReady)
                .Select(d => d.Name[0].ToString())
                .ToArray();

            cmbDrives.Items.AddRange(drives);  // 添加驱动器到下拉框
            if (cmbDrives.Items.Count > 0)
                cmbDrives.SelectedIndex = 0;  // 默认选择第一个驱动器
        }

        private readonly CancellationTokenSource cts = new CancellationTokenSource();
        private bool isDisposed;

        protected override void Dispose(bool disposing)
        {
            if (!isDisposed)
            {
                if (disposing)
                {
                    cts?.Cancel();
                    cts?.Dispose();
                }
                isDisposed = true;
            }
            base.Dispose(disposing);
        }

        private async void btnScan_Click(object sender, EventArgs e)
        {
            btnScan.Enabled = false;
            try
            {
                if (cmbDrives.SelectedItem == null)
                {
                    MessageBox.Show("请先选择驱动器");
                    return;
                }

                string driveLetter = cmbDrives.SelectedItem + ":\\";
                await ScanDriveAsync(driveLetter);
            }
            catch (OperationCanceledException)
            {
                logger.LogInfo("扫描操作已取消");
            }
            catch (Exception ex)
            {
                logger.LogError($"扫描错误: {ex.Message}");
                MessageBox.Show($"扫描过程中发生错误: {ex.Message}", "错误", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                btnScan.Enabled = true;
            }
        }

        /// <summary>
        /// 异步扫描指定驱动器中的可删除文件
        /// </summary>
        /// <param name="drivePath">驱动器路径</param>
        private async Task ScanDriveAsync(string drivePath)
        {
            try
            {
                await UpdateUIAsync(() => 
                {
                    lblStatus.Text = $"扫描中: {drivePath}";
                    listViewFiles.Items.Clear();
                    progressBar.Value = 0;
                    progressBar.Visible = true;
                });

                // 预加载所有目录和文件类型
                var fileTypes = GetFileTypesToScan().ToList();
                var allDirs = new DirectoryInfo(drivePath)
                    .EnumerateDirectories("*", new EnumerationOptions 
                    { 
                        RecurseSubdirectories = true,
                        IgnoreInaccessible = true,
                        AttributesToSkip = FileAttributes.System | FileAttributes.Hidden
                    })
                    .Where(d => !d.FullName.Contains("Windows") && 
                               !d.FullName.Contains("Program Files") &&
                               !d.FullName.Contains("Program Files (x86)"))
                    .Prepend(new DirectoryInfo(drivePath))
                    .ToList();

                // 预计算总大小
                totalBytesToFree = await Task.Run(() => CalculateFreeableSpace(drivePath, allDirs, fileTypes, cts.Token), cts.Token);
                
                var result = await Task.Run(() => ScanFilesParallel(allDirs, fileTypes, cts.Token), cts.Token);


                totalBytesToFree = result.TotalSize;
                listViewFiles.Items.AddRange(result.FileList.ToArray());
                progressBar.Value = 100;
                lblStatus.Text = $"可释放空间: {FormatSize(totalBytesToFree)} (共 {result.FileList.Count} 个文件)";
                btnScan.Enabled = true;
                logger.LogInfo($"扫描完成: 驱动器 {drivePath} 可释放 {FormatSize(totalBytesToFree)}");
            }
            catch (Exception ex)
            {
                logger.LogError($"扫描错误: {ex.Message}");
                btnScan.Enabled = true;
                // 只记录日志，不重新抛出异常
            }
        }

        private DateTime lastUpdate = DateTime.Now;
        private long CalculateFreeableSpace(string path, List<DirectoryInfo> allDirs, List<(string Pattern, Func<FileInfo, bool> Filter)> fileTypes, CancellationToken cancellationToken)
        {
            long size = 0;
            var options = new ParallelOptions 
            { 
                MaxDegreeOfParallelism = Environment.ProcessorCount,
                CancellationToken = cancellationToken
            };

            Parallel.ForEach(allDirs, options, dir =>
            {
                options.CancellationToken.ThrowIfCancellationRequested();
                
                try
                {
                    long dirSize = 0;
                    foreach (var fileType in fileTypes)
                    {
                        try
                        {
                            var files = dir.EnumerateFiles(fileType.Pattern, new EnumerationOptions
                            {
                                RecurseSubdirectories = false,
                                IgnoreInaccessible = true,
                                AttributesToSkip = FileAttributes.System | FileAttributes.Hidden
                            });

                            dirSize += files
                                .Where(f => fileType.Filter == null || fileType.Filter(f))
                                .Where(f => IsFileSafeToDelete(f.FullName))
                                .Sum(f => f.Length);
                        }
                        catch (Exception ex)
                        {
                            logger.LogWarning($"处理目录 {dir.FullName} 时发生错误: {ex.Message}");
                        }
                    }
                    Interlocked.Add(ref size, dirSize);
                }
                catch (Exception ex)
                {
                    logger.LogWarning($"处理目录 {dir.FullName} 时发生错误: {ex.Message}");
                }
            });

            return size;
        }

        private ScanResult ScanFilesParallel(List<DirectoryInfo> allDirs, List<(string Pattern, Func<FileInfo, bool> Filter)> fileTypes, CancellationToken cancellationToken)
        {
            var files = new ConcurrentBag<ListViewItem>();
            long totalSize = 0;
            var lastUpdate = DateTime.Now;
            
            Parallel.ForEach(allDirs, new ParallelOptions
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount,
                CancellationToken = cancellationToken
            }, dir =>
            {
                cancellationToken.ThrowIfCancellationRequested();
                
                try
                {
                    var dirFiles = new List<FileInfo>();
                    foreach (var ft in fileTypes)
                    {
                        dirFiles.AddRange(dir.EnumerateFiles(ft.Pattern, new EnumerationOptions
                        {
                            RecurseSubdirectories = false,
                            IgnoreInaccessible = true,
                            AttributesToSkip = FileAttributes.System | FileAttributes.Hidden
                        })
                        .Where(f => ft.Filter == null || ft.Filter(f)));
                    }

                    var safeFiles = dirFiles
                        .Where(f => IsFileSafeToDelete(f.FullName))
                        .ToList();

                    var items = safeFiles.Select(file => new ListViewItem(new[] {
                        file.Name,
                        file.Length.ToString(),
                        file.DirectoryName
                    })).ToList();

                    if (items.Count > 0)
                    {
                        foreach (var item in items)
                        {
                            files.Add(item);
                        }
                        
                        Interlocked.Add(ref totalSize, safeFiles.Sum(f => f.Length));
                        
                        // 限制UI更新频率
                        if (DateTime.Now - lastUpdate > TimeSpan.FromMilliseconds(500))
                        {
                            lock (this)
                            {
                                if (DateTime.Now - lastUpdate > TimeSpan.FromMilliseconds(500))
                                {
                                    this.Invoke((MethodInvoker)delegate
                                    {
                                        lblStatus.Text = $"扫描中: {dir.FullName}";
                                        UpdateProgress(totalSize, totalBytesToFree);
                                    });
                                    lastUpdate = DateTime.Now;
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    logger.LogError($"扫描目录 {dir.FullName} 错误: {ex.Message}");
                }
            });

            return new ScanResult { TotalSize = totalSize, FileList = files.ToList() };
        }

        private async Task UpdateUIAsync(Action action)
        {
            if (IsDisposed || Disposing)
                return;

            if (InvokeRequired)
            {
                try
                {
                    await InvokeAsync(action);
                }
                catch (ObjectDisposedException)
                {
                    // 窗体已释放，忽略异常
                }
            }
            else
            {
                action();
            }
        }

        private Task InvokeAsync(Action action)
        {
            var tcs = new TaskCompletionSource<bool>();
            BeginInvoke((MethodInvoker)(() => 
            {
                try
                {
                    action();
                    tcs.TrySetResult(true);
                }
                catch (Exception ex)
                {
                    tcs.TrySetException(ex);
                }
            }));
            return tcs.Task;
        }

        private void UpdateProgress(long current, long total)
        {
            if (total <= 0) return;

            int percent = (int)(current * 100 / total);
            percent = Math.Max(0, Math.Min(100, percent));

            // 限制UI更新频率
            if (DateTime.Now - lastUpdate < TimeSpan.FromMilliseconds(200))
                return;

            if (InvokeRequired)
            {
                BeginInvoke((MethodInvoker)(() => UpdateProgress(current, total)));
                return;
            }

            try
            {
                progressBar.Value = percent;
                lblProgress.Text = $"{percent}%";
                
                // 计算剩余时间估计
                if (percent > 5 && percent < 100)
                {
                    var elapsed = DateTime.Now - lastUpdate;
                    var estimatedTotal = elapsed.TotalSeconds * 100 / percent;
                    var remaining = TimeSpan.FromSeconds(estimatedTotal * (100 - percent) / 100);
                    lblStatus.Text = $"处理中: {percent}% (剩余约 {remaining:mm\\:ss})";
                }
                else
                {
                    lblStatus.Text = $"处理中: {percent}%";
                }
                
                lastUpdate = DateTime.Now;
            }
            catch (Exception ex)
            {
                logger.LogWarning($"更新进度条错误: {ex.Message}");
            }
        }

        private async Task UpdateProgressAsync(long current, long total)
        {
            if (total <= 0) return;

            int percent = (int)(current * 100 / total);
            percent = Math.Max(0, Math.Min(100, percent));

            // 限制UI更新频率
            if (DateTime.Now - lastUpdate < TimeSpan.FromMilliseconds(200))
                return;

            try
            {
                await UpdateUIAsync(() => 
                {
                    progressBar.Value = percent;
                    lblProgress.Text = $"{percent}%";
                    
                    // 计算剩余时间估计
                    if (percent > 5 && percent < 100)
                    {
                        var elapsed = DateTime.Now - lastUpdate;
                        var estimatedTotal = elapsed.TotalSeconds * 100 / percent;
                        var remaining = TimeSpan.FromSeconds(estimatedTotal * (100 - percent) / 100);
                        lblStatus.Text = $"处理中: {percent}% (剩余约 {remaining:mm\\:ss})";
                    }
                    else
                    {
                        lblStatus.Text = $"处理中: {percent}%";
                    }
                    
                    lastUpdate = DateTime.Now;
                });
            }
            catch (Exception ex)
            {
                logger.LogWarning($"更新进度条错误: {ex.Message}");
            }
        }

        private IEnumerable<(string Pattern, Func<FileInfo, bool>? Filter)> GetFileTypesToScan()
        {
            if (chkTempFiles.Checked)
            {
                yield return ("*.tmp", null);
                yield return ("~*.*", null);
                yield return ("*.temp", null);
            }

            if (chkLogs.Checked)
            {
                yield return ("*.log", f => (DateTime.Now - f.LastWriteTime).TotalDays > 7);
            }

            if (chkCacheFiles.Checked)
            {
                yield return ("*.cache", null);
                yield return ("Thumbs.db", null);
            }

            // 大文件扫描
            long thresholdBytes = (long)numThreshold.Value * 1024 * 1024;
            yield return ("*.*", f => f.Length >= thresholdBytes);
        }

        /// <summary>
        /// 检查文件是否可以安全删除
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>如果文件可以安全删除返回true，否则返回false</returns>
        private bool IsFileSafeToDelete(string filePath)
        {
            try
            {
                // 检查系统关键文件
                if (IsSystemCriticalFile(filePath))
                    return false;

                // 检查文件属性
                var attr = File.GetAttributes(filePath);
                if ((attr & FileAttributes.System) == FileAttributes.System ||
                    (attr & FileAttributes.Hidden) == FileAttributes.Hidden)
                    return false;

                // 检查文件占用
                using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None))
                {
                    // 额外检查文件是否正在被系统进程使用
                    if (IsFileLockedBySystemProcess(filePath))
                        return false;

                    return true;
                }
            }
            catch (UnauthorizedAccessException)
            {
                logger.LogWarning($"无权限访问文件: {filePath}");
                return false;
            }
            catch (IOException ex) when (ex.Message.Contains("used by another process"))
            {
                return false;
            }
            catch (Exception ex)
            {
                logger.LogError($"检查文件安全删除错误: {filePath} - {ex.Message}");
                return false;
            }
        }

        private bool IsFileLockedBySystemProcess(string filePath)
        {
            try
            {
                var process = new Process
                {
                    StartInfo = new ProcessStartInfo
                    {
                        FileName = "handle64.exe",
                        Arguments = $"-nobanner \"{filePath}\"",
                        UseShellExecute = false,
                        CreateNoWindow = true,
                        RedirectStandardOutput = true
                    }
                };
                process.Start();
                string output = process.StandardOutput.ReadToEnd();
                process.WaitForExit();
                return output.Contains("pid:");
            }
            catch
            {
                return false;
            }
        }

        private bool IsSystemCriticalFile(string filePath)
        {
            var systemDirs = new[] { "Windows", "Program Files", "Program Files (x86)" };
            return systemDirs.Any(dir => filePath.Contains($@"{dir}\"));
        }

        /// <summary>
        /// 清理按钮点击事件处理
        /// </summary>
        private async void btnClean_Click(object sender, EventArgs e)
        {
            btnClean.Enabled = false;
            try
            {
                if (cmbDrives.SelectedItem == null)
                {
                    MessageBox.Show("请先选择驱动器");
                    return;
                }

                string driveLetter = cmbDrives.SelectedItem + ":\\";
                // 显示确认对话框
                if (MessageBox.Show($"确定要清理 {driveLetter} 驱动器吗?", "确认",
                    MessageBoxButtons.YesNo) == DialogResult.Yes)
                {
                    await CleanDriveAsync(driveLetter);  // 异步执行清理操作
                }
            }
            catch (OperationCanceledException)
            {
                logger.LogInfo("清理操作已取消");
            }
            catch (Exception ex)
            {
                logger.LogError($"清理错误: {ex.Message}");
                MessageBox.Show($"清理过程中发生错误: {ex.Message}", "错误", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                btnClean.Enabled = true;
            }
        }

        /// <summary>
        /// 异步清理指定驱动器中的可删除文件
        /// </summary>
        /// <param name="drivePath">驱动器路径</param>
        private async Task CleanDriveAsync(string drivePath)
        {
            try
            {
                await UpdateUIAsync(() => 
                {
                    lblStatus.Text = "清理中...";
                    btnClean.Enabled = false;
                    bytesFreed = 0;
                    progressBar.Value = 0;
                });

                var stopwatch = Stopwatch.StartNew();
                long initialBytesFreed = bytesFreed;

                await Task.Run(() =>
                {
                    try
                    {
                        CleanTempFiles(drivePath);
                    }
                    catch (OperationCanceledException)
                    {
                        logger.LogInfo("清理操作已取消");
                        throw;
                    }
                    catch (Exception ex)
                    {
                        logger.LogError($"清理文件错误: {ex.Message}");
                        throw;
                    }
                }, cts.Token);

                stopwatch.Stop();
                double speed = (bytesFreed - initialBytesFreed) / (stopwatch.Elapsed.TotalSeconds + 0.001) / (1024 * 1024); // MB/s

                await UpdateUIAsync(() => 
                {
                    lblStatus.Text = $"清理完成，释放空间: {FormatSize(bytesFreed)} (速度: {speed:0.0} MB/s)";
                    progressBar.Value = 100;
                    btnClean.Enabled = true;
                });

                logger.LogInfo($"清理完成: 驱动器 {drivePath} 释放 {FormatSize(bytesFreed)}, 耗时 {stopwatch.Elapsed.TotalSeconds:0.0}秒, 平均速度 {speed:0.0} MB/s");
            }
            catch (OperationCanceledException)
            {
                await UpdateUIAsync(() => 
                {
                    lblStatus.Text = "清理已取消";
                    btnClean.Enabled = true;
                });
            }
            catch (Exception ex)
            {
                logger.LogError($"清理错误: {ex.Message}");
                await UpdateUIAsync(() => 
                {
                    lblStatus.Text = $"清理失败: {ex.Message}";
                    btnClean.Enabled = true;
                });
            }
        }

        /// <summary>
        /// 清理指定路径下的临时文件
        /// </summary>
        /// <param name="path">要清理的路径</param>
        private void CleanTempFiles(string path)
        {
            var options = new ParallelOptions 
            { 
                MaxDegreeOfParallelism = Environment.ProcessorCount,
                CancellationToken = cts.Token
            };
            var dir = new DirectoryInfo(path);

            try
            {
                Parallel.ForEach(GetFileTypesToScan(), options, fileType =>
                {
                    options.CancellationToken.ThrowIfCancellationRequested();
                    
                    try
                    {
                        var files = dir.EnumerateFiles(fileType.Pattern, SearchOption.AllDirectories)
                            .Where(f => fileType.Filter == null || fileType.Filter(f))
                            .Where(f => IsFileSafeToDelete(f.FullName))
                            .ToList();

                        foreach (var file in files)
                        {
                            options.CancellationToken.ThrowIfCancellationRequested();
                            
                            try
                            {
                                SecureDelete(file.FullName);
                                Interlocked.Add(ref bytesFreed, file.Length);
                                
                                // 定期更新UI
                                if (DateTime.Now - lastUpdate > TimeSpan.FromMilliseconds(500))
                                {
                                    UpdateUIAsync(() => 
                                    {
                                        lblStatus.Text = $"正在清理: {file.FullName}";
                                        lastUpdate = DateTime.Now;
                                    }).Wait(options.CancellationToken);
                                }
                            }
                            catch (OperationCanceledException)
                            {
                                throw;
                            }
                            catch (Exception ex)
                            {
                                logger.LogWarning($"无法删除文件 {file.FullName}: {ex.Message}");
                            }
                        }
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        logger.LogWarning($"无权限访问目录: {ex.Message}");
                    }
                    catch (OperationCanceledException)
                    {
                        throw;
                    }
                    catch (Exception ex)
                    {
                        logger.LogError($"清理文件时发生错误: {ex.Message}");
                    }
                });
            }
            catch (OperationCanceledException)
            {
                logger.LogInfo("清理操作已取消");
                throw;
            }
        }

        /// <summary>
        /// 安全删除文件(3次覆盖写入后删除)
        /// </summary>
        /// <param name="filePath">要删除的文件路径</param>
        private void SecureDelete(string filePath)
        {
            try
            {
                // 检查文件是否存在
                if (!File.Exists(filePath))
                    return;

                // 3次覆盖写入随机数据
                var random = new Random();
                var buffer = new byte[4096];
                using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Write, FileShare.None, bufferSize: 4096, FileOptions.WriteThrough))
                {
                    for (int i = 0; i < 3; i++)
                    {
                        fs.Position = 0;
                        random.NextBytes(buffer);
                        fs.Write(buffer, 0, buffer.Length);
                        fs.Flush();
                    }
                }

                // 重置文件属性
                File.SetAttributes(filePath, FileAttributes.Normal);

                // 删除文件
                File.Delete(filePath);

                // 尝试删除空文件夹
                var dir = Path.GetDirectoryName(filePath);
                while (!string.IsNullOrEmpty(dir) && Directory.Exists(dir) && 
                       !Directory.EnumerateFileSystemEntries(dir).Any())
                {
                    try
                    {
                        Directory.Delete(dir);
                    }
                    catch (Exception ex)
                    {
                        logger.LogWarning($"无法删除空目录 {dir}: {ex.Message}");
                        break;
                    }
                    dir = Path.GetDirectoryName(dir);
                }
            }
            catch (UnauthorizedAccessException ex)
            {
                logger.LogWarning($"无权限安全删除文件 {filePath}: {ex.Message}");
            }
            catch (IOException ex)
            {
                logger.LogError($"安全删除文件IO错误 {filePath}: {ex.Message}");
            }
            catch (Exception ex)
            {
                logger.LogError($"安全删除失败 {filePath}: {ex.Message}");
            }
        }


        /// <summary>
        /// 格式化文件大小为易读的字符串
        /// </summary>
        /// <param name="bytes">文件大小(字节)</param>
        /// <returns>格式化后的字符串(如"1.23 MB")</returns>
        private string FormatSize(long bytes)
        {
            string[] sizes = { "B", "KB", "MB", "GB" };
            int order = 0;
            while (bytes >= 1024 && order < sizes.Length - 1)
            {
                order++;
                bytes /= 1024;
            }
            return $"{bytes:0.##} {sizes[order]}";
        }
    }

    public class ScanResult
    {
        public long TotalSize { get; set; }
        public List<ListViewItem> FileList { get; set; } = new List<ListViewItem>();
    }
}